package com.qs.security.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.qs.security.config.RsaKeyProperties;
import com.qs.security.domain.SysRole;
import com.qs.security.domain.SysUser;
import com.qs.security.utils.JwtUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {

    private static Logger logger = LoggerFactory.getLogger(TokenLoginFilter.class);

    private AuthenticationManager authenticationManager;

    private RsaKeyProperties prop;

    public TokenLoginFilter(AuthenticationManager authenticationManager, RsaKeyProperties prop) {
        this.authenticationManager = authenticationManager;
        this.prop = prop;
    }

    /**
     * 接收并解析用户凭证，出现错误时，返回json数据
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
        try {
            SysUser sysUser = new ObjectMapper().readValue(request.getInputStream(), SysUser.class);
            logger.info("\n获取到登录表单参数，封装为sysUser对象，sysUser={}", sysUser);
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(sysUser.getUsername(), sysUser.getPassword());
            return authenticationManager.authenticate(authenticationToken);
        } catch (Exception e) {
            logger.error("\n认证失败，返回自定义异常");
            //如果认证失败，提供自定义json格式异常
            Map<String, Object> respMap = new HashMap<>();
            respMap.put("code", HttpServletResponse.SC_UNAUTHORIZED);
            respMap.put("message", "账户或密码错误");
            responseMsg(respMap, response);
            throw new RuntimeException(e);
        }
    }

    /**
     * 用户登录成功后，生成token，并且返回数据给前端
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                            FilterChain chain, Authentication authResult) throws IOException, ServletException {
        //得到当前认证的用户对象
        SysUser user = new SysUser();
        user.setUsername(authResult.getName());
        user.setRoles((List<SysRole>) authResult.getAuthorities());

        //生成jwt token
        String jwtToken = JwtUtils.generateTokenExpireInMinutes(user, prop.getPrivateKey(), 24 * 60);
        //将token存储header中返回
        response.setHeader("Authorization", "Bearer" + jwtToken);
        Map<String, Object> respMap = new HashMap<>();
        respMap.put("code", HttpServletResponse.SC_OK);
        respMap.put("message", "登陆成功");
        responseMsg(respMap, response);
    }

    //response响应自定义json
    private void responseMsg(Map<String, Object> respMap, HttpServletResponse response) {
        try {
            response.setContentType("application/json;charset=utf-8");
            response.setStatus((Integer) respMap.get("code"));
            PrintWriter out = response.getWriter();
            out.write(new ObjectMapper().writeValueAsString(respMap));
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
